package vip.sweet.web.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import vip.sweet.common.enums.ResponseEnum;
import vip.sweet.common.response.CommonResponse;
import vip.sweet.common.utils.JwtUtil;
import vip.sweet.common.utils.RedisUtil;
import vip.sweet.sys.modular.login.service.impl.SecurityUserDetailImpl;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author ASUS
 * @Date 2025/7/13 17:22
 * @Descripition
 */
@Component
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Resource
    private SecurityUserDetailImpl securityUserDetailImpl;
    @Resource
    private JwtUtil jwtUtil;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 拦截器
     *
     * @param request 请求
     * @param response 响应
     * @throws ServletException Servlet异常
     * @throws IOException IO异常,也就是输出流，输出流是往响应体里写数据，也就是往浏览器写数据
     */

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain chain) throws IOException, ServletException {
        String token = request.getHeader(JwtUtil.HEADER);
        // 未获取到token，继续往后走，因为后面还有鉴权管理器等去判断是否拥有身份凭证，所以可以放行
        // 没有token相当于匿名访问，若有一些接口是需要权限的，则不能访问这些接口
        if (StrUtil.isBlankOrUndefined(token)) { // 未获取到token
            chain.doFilter(request, response);
            return; // 返回json数据,不再继续执行，直接返回json数据
        }
        Claims claims = jwtUtil.getClaimsByToken(token);
        if (jwtUtil.isTokenExpired(claims.getExpiration()) || !redisUtil.hasKey("token-" + token)) {
            returnJson(response, JSON.toJSONString(CommonResponse.error(ResponseEnum.FORBIDDEN, "用户登录已过期")));
            return; // 返回json数据,不再继续执行，直接返回json数据
        }
        String username = claims.getSubject();

        // 构建UsernamePasswordAuthenticationToken，这里密码为null，是因为提供了正确的token，实现自动登录
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, securityUserDetailImpl.getUserAuthority(username));
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));// 将token信息添加到上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }

    private void returnJson(ServletResponse response, String json) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try (PrintWriter writer = response.getWriter()) {
            writer.print(json);
        } catch (IOException e) {
            log.error("response error", e);
        }
    }

}
